Completed
Pull Request — master (#161)
by
unknown
01:21
created

$j.ready   B

Complexity

Conditions 1
Paths 2

Size

Total Lines 351

Duplication

Lines 0
Ratio 0 %

Importance

Changes 12
Bugs 2 Features 0
Metric Value
cc 1
c 12
b 2
f 0
nc 2
nop 0
dl 0
loc 351
rs 8.2857

24 Functions

Rating   Name   Duplication   Size   Complexity  
A 0 8 3
A 0 5 1
A 0 16 3
C 0 44 8
B 0 30 2
A 0 9 2
A 0 7 1
A 0 4 1
A 0 7 2
A 0 6 2
A 0 14 2
B 0 20 5
A 0 12 1
A 0 7 1
A 0 4 1
A 0 6 2
A 0 15 2
A 0 14 2
B 0 45 1
A 0 10 1
A 0 7 1
A 0 6 2
A 0 4 1
A 0 3 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/* global API */
2
var $j = jQuery.noConflict();
3
4
$j(document).ready(function () {
5
6
    $j(document).click(function (event) {
7
        var passwordPickerRef = '.passwordPickerIframe';
8
        if (!$j(event.target).closest(passwordPickerRef).length) {
9
            if ($j(passwordPickerRef).is(":visible")) {
10
                removePasswordPicker();
11
            }
12
        }
13
    });
14
15
    var _this = this;
16
    Array.prototype.findUrl = function (match) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Array. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
17
        return this.filter(function (item) {
18
            return typeof item === 'string' && item.indexOf(match) > -1;
19
        });
20
    };
21
22
    function removePasswordPicker() {
23
        activeForm = undefined;
24
        $j('.passwordPickerIframe').remove();
25
    }
26
27
    _this.removePasswordPicker = removePasswordPicker;
28
29
    function enterLoginDetails(login, allowSubmit) {
30
        var username;
31
32
        if (login.hasOwnProperty('username')) {
33
            username = (login.username !== '' ) ? login.username : login.email;
34
        }
35
        if (!username) {
36
            username = null;
37
        }
38
39
        fillPassword(username, login.password);
40
41
        if (activeForm) {
42
            API.runtime.sendMessage(API.runtime.id, {method: 'isAutoSubmitEnabled'}).then(function (isEnabled) {
43
                if (isEnabled && allowSubmit) {
44
                    submitLoginForm(username);
45
                }
46
            });
47
        }
48
    }
49
50
    _this.enterLoginDetails = enterLoginDetails;
51
52
    function submitLoginForm(username) {
53
        if (!activeForm) {
54
            // @TODO detect login form on the current page
55
            return;
56
        }
57
58
        var formEl = $j(activeForm).closest('form');
59
        var iframeUrl = API.extension.getURL('/html/inject/auto_login.html');
60
        $j('#loginPopupIframe').remove();
61
        var loginPopup = $j('<iframe class="loginPopupIframe" scrolling="no" frameborder="0" src="' + iframeUrl + '"></iframe>');
62
        var padding = parseInt($j(formEl).css('padding').replace('px', ''));
63
        var margin = parseInt($j(formEl).css('margin').replace('px', ''));
64
        var height = Math.round($j(formEl).height() + (padding * 2) + (margin * 2));
65
        var width = Math.round($j(formEl).width() + (padding * 2) + (margin * 2));
66
        loginPopup.attr('height', height);
67
        loginPopup.attr('width', width);
68
        loginPopup.css('position', 'absolute');
69
        loginPopup.css('z-index', getMaxZ() + 1);
70
        loginPopup.css('background-color', 'rgba(0, 0, 0, 0.73)');
71
        loginPopup.css('left', Math.floor($j(formEl).offset().left - padding - margin));
72
        loginPopup.css('top', Math.floor($j(formEl).offset().top - padding - margin));
73
        removePasswordPicker();
74
        $j(document.body).prepend(loginPopup);
75
        API.runtime.sendMessage(API.runtime.id, {'setIframeUsername': username}).then(function () {
76
            $j(formEl).submit();
77
            setTimeout(function () {
78
                loginPopup.remove();
79
            }, 2000);
80
        });
81
    }
82
83
    function getMaxZ() {
84
        return Math.max.apply(null,
85
            $j.map($j('body *'), function (e) {
86
                if ($j(e).css('position') !== 'static')
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $j(e).css("position") !== "static" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
87
                    return parseInt($j(e).css('z-index')) || 1;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
88
            }));
89
    }
90
91
    var activeForm;
92
93
    function showPasswordPicker(form) {
94
        var jPasswordPicker = $j('.passwordPickerIframe');
95
        if (jPasswordPicker.length > 1) {
96
            return;
97
        }
98
        var loginField = $j(form[0]);
99
        var loginFieldPos = loginField.offset();
100
        var loginFieldVisible = loginField.is(':visible');
101
102
        var position = $j(form[1]).position();
0 ignored issues
show
Unused Code introduced by
The assignment to variable position seems to be never used. Consider removing it.
Loading history...
103
        var passwordField = $j(form[1]);
104
        var passwordFieldPos = passwordField.offset();
105
        var passwordFieldVisible = loginField.is(':visible');
0 ignored issues
show
Unused Code introduced by
The variable passwordFieldVisible seems to be never used. Consider removing it.
Loading history...
106
        var left = (loginFieldPos) ? loginFieldPos.left : passwordFieldPos.left;
107
        var top = (loginFieldPos) ? loginFieldPos.top : passwordFieldPos.top;
108
        var maxZ = getMaxZ();
109
110
        if (loginFieldPos && passwordFieldPos.top > loginFieldPos.top) {
111
            //console.log('login fields below each other')
112
            top = passwordFieldPos.top + passwordField.height() + 10;
113
        } else {
114
            // console.log('login fields next to each other')
115
            if (loginFieldPos) {
116
                top = top + loginField.height() + 10;
117
            } else {
118
                top = top + passwordField.height() + 10;
119
            }
120
        }
121
        if (!loginFieldVisible) {
122
            left = passwordFieldPos.left;
123
        }
124
125
        var pickerUrl = API.extension.getURL('/html/inject/password_picker.html');
126
127
        var picker = $j('<iframe class="passwordPickerIframe" scrolling="no" height="385" width="350" frameborder="0" src="' + pickerUrl + '"></iframe>');
128
        picker.css('position', 'absolute');
129
        picker.css('left', left);
130
        picker.css('z-index', maxZ + 10);
131
        picker.css('top', top);
132
        $j('body').prepend($j(picker));
133
        activeForm = form;
134
        // picker.css('width', $j(form).width());
135
        $j('.passwordPickerIframe:not(:last)').remove();
136
    }
137
138
    function onFormIconClick(e) {
139
        e.preventDefault();
140
        e.stopPropagation();
141
        var offsetX = e.offsetX;
142
        var offsetRight = (e.data.width - offsetX);
143
        if (offsetRight < e.data.height) {
144
            showPasswordPicker(e.data.form);
145
        }
146
    }
147
148
    function createFormIcon(el, form) {
149
        var offset = el.offset();
0 ignored issues
show
Unused Code introduced by
The assignment to variable offset seems to be never used. Consider removing it.
Loading history...
150
        var width = el.width();
151
        var height = el.height() * 1;
152
        var margin = (el.css('margin')) ? parseInt(el.css('margin').replace('px', '')) : 0;
0 ignored issues
show
Unused Code introduced by
The variable margin seems to be never used. Consider removing it.
Loading history...
153
        var padding = (el.css('padding')) ? parseInt(el.css('padding').replace('px', '')) : 0;
0 ignored issues
show
Unused Code introduced by
The variable padding seems to be never used. Consider removing it.
Loading history...
154
155
        var pickerIcon = API.extension.getURL('/icons/icon.svg');
156
        $j(el).css('background-image', 'url("' + pickerIcon + '")');
157
        $j(el).css('background-repeat', 'no-repeat');
158
        //$j(el).css('background-position', '');
159
        $j(el).css('cssText', el.attr('style') + ' background-position: right 3px center !important;');
160
161
        $j(el).unbind('click', onFormIconClick);
162
        $j(el).click({width: width, height: height, form: form}, onFormIconClick);
163
    }
164
165
    function createPasswordPicker(form) {
166
        for (var i = 0; i < form.length; i++) {
167
            var el = $j(form[i]);
168
            createFormIcon(el, form);
169
        }
170
    }
171
172
    function formSubmitted(fields) {
173
        var user = fields[0].value;
174
        var pass = fields[1].value;
175
        var params = {
176
            username: user,
177
            password: pass
178
        };
179
        //Disable password mining
180
        //$j(fields[1]).attr('type', 'hidden');
181
        API.runtime.sendMessage(API.runtime.id, {method: "minedForm", args: params});
182
183
    }
184
185
    function inIframe() {
186
        try {
187
            return window.self !== window.top;
188
        } catch (e) {
189
            return true;
190
        }
191
    }
192
193
    function showDoorhanger(data) {
194
        if (inIframe()) {
195
            return;
196
        }
197
        data.data.currentLocation = window.location.href;
198
        API.runtime.sendMessage(API.runtime.id, {method: "setDoorhangerData", args: data});
199
        var pickerUrl = API.extension.getURL('/html/inject/doorhanger.html');
200
201
        var doorhanger = $j('<iframe id="password-toolbarIframe" style="display: none;" scrolling="no" height="60" width="100%" frameborder="0" src="' + pickerUrl + '"></iframe>');
202
        $j('#password-toolbarIframe').remove();
203
        doorhanger.css('z-index', getMaxZ() + 1);
204
        $j('body').prepend(doorhanger);
205
        $j('#password-toolbarIframe').fadeIn();
206
    }
207
208
    _this.showDoorhanger = showDoorhanger;
209
210
    function showUrlUpdateDoorhanger(data) {
211
        var buttons = ['cancel', 'updateUrl'];
212
        showDoorhanger({
213
            data: data.data,
214
            buttons: buttons
215
        });
216
    }
217
218
    _this.showUrlUpdateDoorhanger = showUrlUpdateDoorhanger;
219
220
    function showSavedCredentialDoorhanger() {
221
        var buttons = ['cancel'];
222
        showDoorhanger({
223
            data: {},
224
            buttons: buttons
225
        });
226
    }
227
228
    _this.showSavedCredentialDoorhanger = showSavedCredentialDoorhanger;
229
230
    function checkForMined() {
231
        if (inIframe()) {
232
            return;
233
        }
234
235
        API.runtime.sendMessage(API.runtime.id, {method: "getMinedData"}).then(function (data) {
236
            if (!data) {
237
                return;
238
            }
239
            if (data.hasOwnProperty('username') && data.hasOwnProperty('password') && data.hasOwnProperty('url')) {
240
                var buttons = ['cancel', 'ignore', 'save'];
241
                showDoorhanger({data: data, buttons: buttons});
242
            }
243
        });
244
    }
245
246
247
    function closeDoorhanger() {
248
        $j('#password-toolbarIframe').hide(400);
249
        $j('#password-toolbarIframe').remove();
250
    }
251
252
    _this.closeDoorhanger = closeDoorhanger;
253
254
    function initForms() {
255
        API.runtime.sendMessage(API.runtime.id, {method: 'getRuntimeSettings'}).then(function (settings) {
256
            var enablePasswordPicker = settings.enablePasswordPicker;
257
            var url = window.location.href;
258
            var loginFields = getLoginFields();
259
            if (!settings.hasOwnProperty('ignored_sites') || settings.ignored_sites.findUrl(url).length !== 0) {
260
                return;
261
            }
262
263
            if (loginFields.length > 0) {
264
                for (var i = 0; i < loginFields.length; i++) {
265
                    var form = getFormFromElement(loginFields[i][0]);
266
                        if (enablePasswordPicker) {
267
                            createPasswordPicker(loginFields[i], form);
0 ignored issues
show
Bug introduced by
The call to createPasswordPicker seems to have too many arguments starting with form.
Loading history...
268
                        }
269
270
                        //Password miner
271
                        /* jshint ignore:start */
272
                        $j(form).submit((function (loginFields) {
273
                            return function () {
274
                                formSubmitted(loginFields);
275
                            };
276
                        })(loginFields[i]));
277
                        /* jshint ignore:end */
278
                }
279
280
281
                API.runtime.sendMessage(API.runtime.id, {
282
                    method: "getCredentialsByUrl",
283
                    args: url
284
                }).then(function (logins) {
285
                    console.log('Found ' + logins.length + ' logins for this site');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
286
                    if (logins.length === 1) {
287
                        API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) {
288
                            if (isEnabled) {
289
                                enterLoginDetails(logins[0], false);
290
                            }
291
                        });
292
                    }
293
294
                });
295
            }
296
297
        });
298
    }
299
300
    function minedLoginSaved(args) {
301
        // If the login added by the user then this is true
302
        if (args.selfAdded) {
303
            enterLoginDetails(args.credential, false);
304
        }
305
    }
306
307
    _this.minedLoginSaved = minedLoginSaved;
308
309
    function resizeIframe(height) {
310
        $j('#password-toolbarIframe').height(60 + height);
311
    }
312
313
    _this.resizeIframe = resizeIframe;
314
315
    function copyText(text) {
316
        var txtToCopy = document.createElement('input');
317
        txtToCopy.style.left = '-300px';
318
        txtToCopy.style.position = 'absolute';
319
        txtToCopy.value = text;
320
        document.body.appendChild(txtToCopy);
321
        txtToCopy.select();
322
        document.execCommand('copy');
323
        txtToCopy.parentNode.removeChild(txtToCopy);
324
    }
325
326
    _this.copyText = copyText;
327
328
    function init() {
329
        checkForMined();
330
        initForms();
331
    }
332
333
    var readyStateCheckInterval = setInterval(function () {
334
        if (document.readyState === "complete") {
335
            clearInterval(readyStateCheckInterval);
336
            API.runtime.sendMessage(API.runtime.id, {method: 'getMasterPasswordSet'}).then(function (result) {
337
                if (result) {
338
                    init();
339
                    var body = document.getElementsByTagName('body')[0];
340
                    observeDOM(body, initForms);
341
                } else {
342
                    console.log('[Passman extension] Stopping, vault key not set');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
343
                }
344
            });
345
        }
346
    }, 10);
347
348
    API.runtime.onMessage.addListener(function (msg, sender) {
349
        //console.log('Method call', msg.method);
350
        if (_this[msg.method]) {
351
            _this[msg.method](msg.args, sender);
352
        }
353
    });
354
});
355